package com.ziyun.pop.common.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.utility.DoubleSerializer;
import com.utility.IntArrayDeserializer;
import com.ziyun.pop.common.e.BaseEnum;
import org.apache.commons.beanutils.BeanUtils;
import org.codehaus.jackson.Version;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.module.SimpleModule;
import org.codehaus.jackson.map.type.ArrayType;
import org.codehaus.jackson.map.type.TypeFactory;
import org.codehaus.jackson.type.JavaType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * json 工具类
 * 
 * @author guizhao
 * @date 2017年11月7日 上午11:28:32
 */
public class JsonUtils {
	private JsonUtils() {
		throw new IllegalAccessError("该类不允许实例化");
	}

	private static final Logger log = LoggerFactory.getLogger(com.utility.JsonUtils.class);

	private static final ObjectMapper mapper;

	private static final ObjectMapper ignoreNullMapper;

	static {
		mapper = new ObjectMapper();
		mapper.enable(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
		SimpleModule module = new SimpleModule("Custom", new Version(1, 0, 0, null));
		module.addDeserializer(int[].class, new IntArrayDeserializer());
		module.addSerializer(Double.class, DoubleSerializer.INSTANCE);
		module.addSerializer(Double.TYPE, DoubleSerializer.INSTANCE);
		mapper.registerModule(module);

		ignoreNullMapper = new ObjectMapper();
		ignoreNullMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
		ignoreNullMapper.configure(SerializationConfig.Feature.WRITE_NULL_MAP_VALUES, false);

		ignoreNullMapper.enable(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
		SimpleModule moduleNull = new SimpleModule("Custom", new Version(1, 0, 0, null));
		moduleNull.addDeserializer(int[].class, new IntArrayDeserializer());
		moduleNull.addSerializer(Double.class, DoubleSerializer.INSTANCE);
		moduleNull.addSerializer(Double.TYPE, DoubleSerializer.INSTANCE);
		ignoreNullMapper.registerModule(moduleNull);

	}

	/**
	 * 将对象转换为 JSON 的字符串格式
	 *
	 * @param object
	 * @return
	 */
	public static String object2String(Object object) {
		return object2String(object, false);
	}

	public static String object2String(Object object, boolean prettyFormat) {
		StringWriter writer = new StringWriter();
		try {
			if (prettyFormat) {
				mapper.writerWithDefaultPrettyPrinter().writeValue(writer, object);
			} else {
				mapper.writeValue(writer, object);
			}
		} catch (Exception e) {
			log.error("将 object 转换为 json 字符串时发生异常:{}", e);
			return null;
		}
		return writer.toString();
	}

	public static String object2StringIgnoreNullField(Object object) {
		return object2StringIgnoreNullField(object, false);
	}

	public static String object2StringIgnoreNullField(Object object, boolean prettyFormat) {
		StringWriter writer = new StringWriter();
		try {
			if (prettyFormat) {
				ignoreNullMapper.writerWithDefaultPrettyPrinter().writeValue(writer, object);
			} else {
				ignoreNullMapper.writeValue(writer, object);
			}
		} catch (Exception e) {
			log.error("将 object 转换为 json 字符串时发生异常:{}", e);
			return null;
		}
		return writer.toString();
	}

	/**
	 * 将 map 转换为 JSON 的字符串格式
	 *
	 * @param map
	 * @return
	 */
	public static String map2String(Map<?, ?> map) {
		StringWriter writer = new StringWriter();
		try {
			mapper.writeValue(writer, map);
		} catch (Exception e) {
			log.error("将 map 转换为 json 字符串时发生异常:{}", e);
			return null;
		}
		return writer.toString();
	}

	/**
	 * 将 JSON 格式的字符串转换为 map
	 *
	 * @param content
	 * @return
	 */
	public static Map<String, Object> string2Map(String content) {
		JavaType type = TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, Object.class);
		// JavaType type = TypeFactory.mapType(HashMap.class, String.class,
		// Object.class);
		try {
			return mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	/**
	 * 将 JSON 格式的字符串转换为 map
	 *
	 * @param content
	 * @return
	 */
	public static Map<String, Integer[]> string2MapInts(String content) {
		JavaType type = TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, Integer[].class);
		// JavaType type = TypeFactory.mapType(HashMap.class, String.class,
		// Object.class);
		try {
			return mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	/**
	 * 将 JSON 格式的字符串转换为 map
	 *
	 * @param content
	 * @return
	 */
	public static Map<String, String> string2MapString(String content) {
		JavaType type = TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, String.class);
		// JavaType type = TypeFactory.mapType(HashMap.class, String.class,
		// Object.class);
		try {
			return mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	/**
	 * 将 JSON 格式的字符串转换为数组
	 *
	 * @param <T>
	 * @param content
	 *            字符串
	 * @param clz
	 *            数组类型
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] string2Array(String content, Class<T> clz) {
		JavaType type = ArrayType.construct(TypeFactory.defaultInstance().constructType(clz), null, null);
		try {
			return (T[]) mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为数组时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	/**
	 * 将 JSON 格式的字符串转换为对象
	 *
	 * @param <T>
	 * @param content
	 *            字符串
	 * @param clz
	 *            对象类型
	 * @return
	 */
	public static <T> T string2Object(String content, Class<T> clz) {
		JavaType type = TypeFactory.defaultInstance().constructType(clz);
		return string2Object(content, type);
	}

	@SuppressWarnings("unchecked")
	public static <T> T string2Object(String content, JavaType type) {
		try {
			return (T) mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为对象[{}]时出现异常",
					new Object[] { content, type, e });
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	/**
	 * 将 JSON 格式的字符串转换为集合
	 *
	 * @param <T>
	 * @param content
	 *            字符串
	 * @param collectionType
	 *            集合类型
	 * @param elementType
	 *            元素类型
	 * @return
	 */
	public static <C extends Collection<E>, E> C string2Collection(String content, Class<C> collectionType,
																   Class<E> elementType) {
		try {
			JavaType type = TypeFactory.defaultInstance().constructCollectionType(collectionType, elementType);
			// JavaType type = TypeFactory.collectionType(collectionType,
			// elementType);
			return mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为集合[{}]时出现异常",
					new Object[] { content, collectionType.getSimpleName(), e });
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> string2Map(String content, Class<K> keyType, Class<V> valueType) {
		JavaType type = TypeFactory.defaultInstance().constructMapType(HashMap.class, keyType, valueType);
		try {
			return (Map<K, V>) mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> string2LinkedHashMap(String content, Class<K> keyType, Class<V> valueType) {
		JavaType type = TypeFactory.defaultInstance().constructMapType(LinkedHashMap.class, keyType, valueType);
		try {
			return (Map<K, V>) mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	public static Map<?, ?> string2Map(String content, JavaType keyType, JavaType valueType) {
		JavaType type = TypeFactory.defaultInstance().constructMapType(HashMap.class, keyType, valueType);
		try {
			return (Map<?, ?>) mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}








	/**
	 * 将一个JSON数据转换为对应的JAVA对象<br/>
	 * JSON数据中键的名称必须和对应JAVA对象中bean字段的名称一致<br/>
	 * 
	 * @param <T>
	 *            java对象值
	 * @param jsonString
	 *            JSON 对象字符
	 * @param cls
	 *            对象class *
	 * @return 返回java对象
	 */
	public static <T> T getJsonToObject(String jsonString, Class<T> cls) {
		return JSONObject.parseObject(jsonString, cls);
	}

	/**
	 * 从json HASH表达式中获取一个map，改map支持嵌套功能
	 * 
	 * @param jsonString
	 *            json HASH表达式
	 * @return 返回map数组
	 */
	public static Map<String, Object> jsonToMap(String jsonString) {
		JSONObject jsonObject = JSONObject.parseObject(jsonString);
		Iterator<String> keyIter = jsonObject.keySet().iterator();
		String key;
		Object value;
		Map<String, Object> valueMap = new HashMap<String, Object>();

		while (keyIter.hasNext()) {
			key = (String) keyIter.next();
			value = jsonObject.get(key);
			valueMap.put(key, value);
		}

		return valueMap;
	}

	/**
	 * 从json HASH表达式中获取一个map，改map支持嵌套功能
	 * @param jsonString json HASH表达式
	 * @return 返回map数组 Map<String, Object>
	 */
	public static Map<String, String> getMapJsonToStr(String jsonString) {
		JSONObject jsonObject = JSONObject.parseObject(jsonString);
		Iterator<String> keyIter = jsonObject.keySet().iterator();
		String key;
		String value;
		Map<String, String> valueMap = new HashMap<String, String>();

		while (keyIter.hasNext()) {
			key = (String) keyIter.next();
			value = jsonObject.get(key).toString();
			valueMap.put(key, value);
		}

		return valueMap;
	}
	
	/**
	 * 从json HASH表达式中获取一个map，改map支持嵌套功能
	 * @param jsonString json HASH表达式
	 * @return 返回map数组  Map<String, Object>
	 */
	public static Map<String, Object> getMapJsonWishStr(String jsonString) {
		JSONObject jsonObject = JSONObject.parseObject(jsonString);
		Iterator<String> keyIter = jsonObject.keySet().iterator();
		String key;
		String value;
		Map<String, Object> valueMap = new HashMap<String, Object>();

		while (keyIter.hasNext()) {
			key = (String) keyIter.next();
			value = jsonObject.get(key).toString();
			valueMap.put(key, value);
		}

		return valueMap;
	}

	/**
	 * 从json对象集合表达式中得到一个java对象集合<br/>
	 * JSON数据中键的名称必须和对应JAVA对象中bean字段的名称一致<br/>
	 * @param jsonString json字符串
	 * @param cls	JAVA Bean对象
	 * @return JAVA bean对象集合list
	 */
	public static List<?> queryJsonToList(String jsonString, Class<?> cls) {
		List<?> list = JSONArray.parseArray(jsonString, cls);
		return list;
	}
	

	/**
	 * 枚举转list
	 * 
	 * @param cls
	 *            实现了BaseEnum的子类
	 * @return 转换失败返回null
	 */
	@SuppressWarnings("rawtypes")
	public static List<Map<String, Object>> enumToList(Class cls) {
		List<Map<String, Object>> list = null;
		if (cls != null) {
			list = new ArrayList<Map<String, Object>>();
			try {
				Method method = cls.getDeclaredMethod("values");
				BaseEnum[] be = (BaseEnum[]) method.invoke(cls);

				for (BaseEnum e : be) {
					Map<String, Object> map = new HashMap<String, Object>();
					map.put("id", e.toInt());
					map.put("value", e.toCode());
					map.put("describe", e.toDescribe());
					list.add(map);
				}
			} catch (Exception e) {
				return null;
			}
		}
		return list;

	}

	// Bean --> Map 1: 利用Introspector和PropertyDescriptor 将Bean --> Map
	public static Map<String, Object> transBean2Map(Object obj) {

		if(obj == null){
			return null;
		}
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			for (PropertyDescriptor property : propertyDescriptors) {
				String key = property.getName();
				// 过滤class属性
				if (!key.equals("class")) {
					// 得到property对应的getter方法
					Method getter = property.getReadMethod();
					Object value = getter.invoke(obj);
					if (value !=null){
						map.put(key, value);
					}
				}

			}
		} catch (Exception e) {
			System.out.println("transBean2Map Error " + e);
		}

		return map;

	}

	/**
	 *
	 *
	 * Map转换层Bean，使用泛型免去了类型转换的麻烦。
	 * @param <T>
	 * @param map
	 * @param class1
	 * @return
	 */
	public static <T> T map2Bean(Map<String, String> map, Class<T> class1) {
		T bean = null;
		try {
			bean = class1.newInstance();
			BeanUtils.populate(bean, map);
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return bean;
	}

	/* 将Map转换为对象
	* @param paramMap
	* @param cls
	* @return
	*/
	public static <T> T parseMap2Object(Map<String, Object> paramMap, Class<T> cls) {
		return JSONObject.parseObject(JSONObject.toJSONString(paramMap), cls);
	}
}
